//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __THDPOOL_H__
#define __THDPOOL_H__

class CProcess;

const UInt32 c_uDefaultPoolCapacity = 3;

class ThreadPool
{
public:
    void Initialize(CProcess *pOwner);

    ECode GetThread(
        Thread **ppThread,
        ScheduleClass *pScheduleClass,
        uint_t uSchedulePolicy);

    ECode CreateKernelThread(
        threadroutine_t threadroutine,
        void *pArg,
        UInt32 dwFlags,
        ScheduleClass *pScheduleClass,
        uint_t uSchedulePolicy,
        IThread **ppIThread);

    void PutBackThread(Thread *pThread);

    inline Thread *FindThread(
        ScheduleClass *pScheduleClass, uint_t uSchedulePolicy);

    inline void SetCapacity(UInt32 uCapacity);

#ifdef DEBUG_KMUTEX
    ThreadPool(): m_threadLock(__FILE__, __LINE__) {}
#endif //DEBUG_KMUTEX
    
    ~ThreadPool();

private:
    ECode CreateThread(
        Thread **ppThread,
        ScheduleClass *pScheduleClass,
        uint_t uSchedulePolicy);

    void DestroyThread(Thread *pThread);

public:
    CProcess        *m_pOwner;
    UInt32          m_uCapacity;

    DLinkNode       m_threadList;
    UInt32          m_cThreads;
    KMutex          m_threadLock;
};

inline void ThreadPool::Initialize(CProcess *pOwner)
{
    m_pOwner = pOwner;
    m_uCapacity = c_uDefaultPoolCapacity;
    m_cThreads = 0;
    m_threadList.Initialize();
}

inline void ThreadPool::SetCapacity(UInt32 uCapacity)
{
    m_uCapacity = uCapacity;
}

inline Thread *ThreadPool::FindThread(
    ScheduleClass *pScheduleClass, uint_t uSchedulePolicy)
{
    if (0 == m_cThreads) return NULL;

    InProcessLinkNode *pInProcessLinkNode;
    ForEachDLinkNode(InProcessLinkNode *, pInProcessLinkNode, &m_threadList) {
        Thread *pThread = THIS(pInProcessLinkNode, Thread, m_inProcLink);

        if (pScheduleClass == pThread->m_pScheduleClass
            && uSchedulePolicy == pThread->m_uSchedulePolicy) {
            return pThread;
        }
    }

    return NULL;
}

#define PUSH_ARG(uStackTop, arg) \
    do { \
        uStackTop -= 4; \
        *(UInt32*)uStackTop = arg; \
    } while(0)

#endif // __THDPOOL_H__
